﻿'
' Copyright (c) 2012 Kyle Hayward
' 
' Permission is hereby granted, free of charge, to any person obtaining a copy
' of this software and associated documentation files (the "Software"), to deal
' in the Software without restriction, including without limitation the rights
' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
' copies of the Software, and to permit persons to whom the Software is
' furnished to do so, subject to the following conditions:
' 
' The above copyright notice and this permission notice shall be included in
' all copies or substantial portions of the Software.
' 
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
' THE SOFTWARE.
'

Imports System.IO

Imports OptixDotNet
Imports OptixDotNet.Utils
Imports OptixDotNet.Math
Imports OptixDotNetUtils

Public Class VBSample
    Inherits OptixForm

    Public Sub New()
        Utils.DetectGPUCompatibility()

        AddHandler Application.Idle, AddressOf Me.OnIdle
    End Sub

    Protected Overrides Sub Initialize()
        Dim rayGenPath As String = Path.GetFullPath("../../Assets/Cuda/pinhole_camera.ptx")
        Dim shaderPath As String = Path.GetFullPath("../../Assets/Cuda/normal_shader.ptx")
        Dim modelPath As String = Path.GetFullPath("../../Assets/Models/cow.obj")

        '*-----------------------------------------------
        '* Create the Optix context
        '*-----------------------------------------------
        Context = New Context()
        Context.RayTypeCount = 1
        Context.EntryPointCount = 1

        '*-----------------------------------------------
        '* Create the material that will be executed when there is an intersection
        '*-----------------------------------------------
        Dim material As Material = New Material(Context)
        material.Programs(0) = New SurfaceProgram(Context, RayHitType.Closest, shaderPath, "closest_hit_radiance")

        '*-----------------------------------------------
        '* Load the geometry
        '*-----------------------------------------------
        Dim model As OptixOBJLoader = New OptixOBJLoader(modelPath, Context, Nothing, material)
        model.GeoGroup = New GeometryGroup(Context)
        model.Material = material

        Dim intersectPath As String = Path.GetFullPath("../../Assets/Cuda/triangle_mesh.ptx")
        model.IntersecitonProgPath = intersectPath
        model.BoundingBoxProgPath = intersectPath
        model.IntersecitonProgName = "mesh_intersect"
        model.BoundingBoxProgName = "mesh_bounds"
        model.ParseMaterials = False

        model.LoadContent()

        '*-----------------------------------------------
        '* Create the output buffer
        '*-----------------------------------------------
        CreateOutputBuffer(Format.UByte4)

        '*-----------------------------------------------
        '* Create the ray-generation and exception programs
        '*-----------------------------------------------
        Dim rayGen As Program = New Program(Context, rayGenPath, "pinhole_camera")
        Dim exception As Program = New Program(Context, rayGenPath, "exception")
        Dim miss As Program = New Program(Context, shaderPath, "miss")
        miss("bg_color").Set(100 / 255.0F, 149 / 255.0F, 237 / 255.0F)

        Context.SetRayGenerationProgram(0, rayGen)
        Context.SetExceptionProgram(0, exception)
        Context.SetRayMissProgram(0, miss)

        '*-----------------------------------------------
        '* Finally compile the optix context, and build the accel tree
        '*-----------------------------------------------
        SetCamera(model.BBox)

        Context("top_object").Set(model.GeoGroup)
        Context("output_buffer").Set(OutputBuffer)
        Context("scene_epsilon").Set(0.0003F)
        Context("radiance_ray_type").Set(CType(0, UInteger))
        Context("bad_color").SetFloat3(New Vector3(1.0F, 0.0F, 0.0F))

        Console.Write("Compiling Optix... ")
        Dim start As Single = Time.GetTimeInSecs()

        Context.Compile()
        Context.BuildAccelTree()

        Console.WriteLine("{0:0.00}s", Time.GetTimeInSecs() - start)

        RaysTracedPerFrame = Width * Height
    End Sub

    Protected Overrides Sub RayTrace()
        Context.Launch(0, Width, Height)
    End Sub

    Protected Sub SetCamera(ByVal box As BoundingBox)
        Camera = New Camera()
        Camera.Aspect = (CType(Width, Single)) / Height
        Camera.Fov = 30.0
        Camera.RotationVel = 100.0
        Camera.TranslationVel = 100.0

        Camera.CenterOnBoundingBox(box)
        CameraUpdate()

    End Sub

    Protected Overrides Sub CameraUpdate()
        Dim eye = Camera.Position
        Dim right = Camera.Right
        Dim up = Camera.Up
        Dim look = Camera.Look

        Context("eye").Set(eye)
        Context("U").Set(right)
        Context("V").Set(up)
        Context("W").Set(look)
    End Sub
End Class

